﻿/*
 * Copyright (c) 2003-2020 by AG-Software <info@ag-software.de>
 *
 * All Rights Reserved.
 * See the COPYING file for more information.
 *
 * This file is part of the MatriX project.
 *
 * NOTICE: All information contained herein is, and remains the property
 * of AG-Software and its suppliers, if any.
 * The intellectual and technical concepts contained herein are proprietary
 * to AG-Software and its suppliers and may be covered by German and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 *
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from AG-Software.
 *
 * Contact information for AG-Software is available at http://www.ag-software.de
 */
namespace Matrix.Extensions.Client.PubSub
{
    using Matrix.Xmpp.Client;
    using Matrix.Xmpp.PubSub;
    using Matrix.Xmpp.PubSub.Event;
    using Xmpp;
    using Item = Matrix.Xmpp.PubSub.Item;
    using Retract = Matrix.Xmpp.PubSub.Retract;


    public class PubSubBuilder
    {
        /// <summary>
        /// 
        /// </summary>
        /// <remarks>Instant nodes are nodes whose node is is automatically generated by a pubsub service.</remarks>
        /// <param name="to"></param>
        /// <returns></returns>
        public static Iq CreateInstantNode(Jid to)
        {
            return new PubSubIq
            {
                Type = IqType.Set,
                To = to,
                PubSub = { Create = new Create(), Configure = new Configure() },
            };
        }

        /// <summary>
        /// Creates a new node.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <param name="config">The config.</param>
        /// <returns></returns>
        public static Iq CreateNode(Jid to, string node, Configure config)
        {
            Configure conf = config ?? new Configure();

            return new PubSubIq
            {
                Type = IqType.Set,
                To = to,
                PubSub =
                {
                    Create = new Create { Node = node },
                    Configure = conf
                },
            };
        }

        public static Iq DeleteNode(Jid to, string node)
        {
            return new PubSubOwnerIq
            {
                Type = IqType.Set,
                To = to,
                PubSub = { Delete = new Xmpp.PubSub.Owner.Delete { Node = node } }
            };
        }

        /// <summary>
        /// Builds the modify affiliations stanza.
        /// </summary>
        /// <param name="to">Jid of the PubSub service.</param>
        /// <param name="node">The node.</param>
        /// <param name="affiliations">The affiliations.</param>
        /// <returns></returns>
        public static Iq ModifyAffiliations(Jid to, string node, Xmpp.PubSub.Owner.Affiliation[] affiliations)
        {
            /*
            <iq type='get'
                from='hamlet@denmark.lit/elsinore'
                to='pubsub.shakespeare.lit'
                id='ent1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
                <affiliations node='princely_musings'/>
              </pubsub>
            </iq>
            */

            var affs = new Matrix.Xmpp.PubSub.Owner.Affiliations { Node = node };
            foreach (Xmpp.PubSub.Owner.Affiliation affiliation in affiliations)
            {
                affs.AddAffiliation(affiliation);
            }

            return new PubSubOwnerIq
            {
                Type = IqType.Set,
                To = to,
                PubSub =
                {
                    Affiliations = affs
                },
            };
        }

        public static Iq PublishItems(Jid to, string node, Item[] items)
        {
            var pIq = new PubSubIq
            {
                To = to,
                Type = IqType.Set,
            };

            var publish = new Publish { Node = node };

            foreach (var item in items)
            {
                publish.AddItem(item);
            }

            pIq.PubSub.Publish = publish;

            return pIq;
        }

        /// <summary>
        /// Retracts the item.
        /// </summary>
        /// <param name="to">Jid of the pubsub service for this request</param>
        /// <param name="node"></param>
        /// <param name="itemId"></param>
        /// <returns></returns>
        public static Iq RetractItem(Jid to, string node, string itemId)
        {
            return RetractItems(to, node, new[] { itemId });
        }

        /// <summary>
        /// Retracts the items stanza.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <param name="itemIds">The item ids.</param>
        /// <returns></returns>
        public static Iq RetractItems(Jid to, string node, string[] itemIds)
        {
            var pIq = new PubSubIq
            {
                To = to,
                Type = IqType.Set
            };

            var retract = new Retract { Node = node };

            foreach (var item in itemIds)
            {
                retract.AddItem(new Item { Id = item });
            }

            pIq.PubSub.Retract = retract;

            return pIq;
        }

        /// <summary>
        /// Builds the submit node configuration stanza.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <param name="data">The from of teh node configuration.</param>
        /// <returns></returns>
        public static Iq SubmitNodeConfiguration(Jid to, string node, Xmpp.XData.Data data)
        {
            return new PubSubOwnerIq
            {
                Type = IqType.Set,
                To = to,
                PubSub =
                {
                    Configure = new Xmpp.PubSub.Owner.Configure { Node = node, XData = data }
                },
            };
        }

        public static Iq Subscribe(Jid to, string node, Jid jid)
        {
            return new PubSubIq
            {
                To = to,
                Type = IqType.Set,
                PubSub = { Subscribe = new Subscribe { Node = node, Jid = jid } }
            };
        }

        /// <summary>
        /// Builds a unsubscribe stanza.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <param name="jid">The jid.</param>
        /// <returns></returns>
        public static Iq Unsubscribe(Jid to, string node, Jid jid)
        {
            return Unsubscribe(to, node, null, jid);
        }

        /// <summary>
        /// Builds a unsubscribe stanza.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <param name="subId">The sub id.</param>
        /// <param name="jid">The jid.</param>
        /// <returns></returns>
        public static Iq Unsubscribe(Jid to, string node, string subId, Jid jid)
        {
            return new PubSubIq
            {
                To = to,
                Type = IqType.Set,
                PubSub =
                {
                    Unsubscribe = new Unsubscribe
                    {
                        Node = node,
                        Jid = jid,
                        SubId = subId
                    }
                }
            };
        }

        public static Iq RequestAllSubscriptions(Jid to)
        {
            /*
            <iq type='get'
                from='francisco@denmark.lit/barracks'
                to='pubsub.shakespeare.lit'
                id='subscriptions1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub'>
                <subscriptions/>
              </pubsub>
            </iq>
            */
            return new PubSubIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                    Subscriptions = new Subscriptions()
                },
            };
        }

        /// <summary>
        /// Builds the purge node stanza.
        /// </summary>
        /// <param name="to">Jid of the pubsub service for this request</param>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        public static Iq PurgeNode(Jid to, string node)
        {
            var pIq = new PubSubOwnerIq
            {
                To = to,
                Type = IqType.Set,
                PubSub = { Type = Xmpp.PubSub.Owner.PubSubOwnerType.Purge }
            };

            pIq.PubSub.Purge.Node = node;

            return pIq;
        }

        /// <summary>
        /// Requests the node configuration stanza.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        public static Iq RequestNodeConfiguration(Jid to, string node)
        {
            /*
            <iq type='get'
                from='hamlet@denmark.lit/elsinore'
                to='pubsub.shakespeare.lit'
                id='config1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
                <configure node='princely_musings'/>
              </pubsub>
            </iq>
            */
            return new PubSubOwnerIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                    Configure = new Xmpp.PubSub.Owner.Configure {Node = node}
                },
            };
        }

        public static Iq RequestAffiliationsList(Jid to, string node)
        {
            /*
            <iq type='get'
                from='hamlet@denmark.lit/elsinore'
                to='pubsub.shakespeare.lit'
                id='ent1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
                <affiliations node='princely_musings'/>
              </pubsub>
            </iq>
            */
            return new PubSubOwnerIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                    Affiliations = new Xmpp.PubSub.Owner.Affiliations { Node = node }
                },
            };
        }

        public static Iq RequestSubscriptions(Jid to, string node)
        {
            /*
            <iq type='get'
                from='francisco@denmark.lit/barracks'
                to='pubsub.shakespeare.lit'
                id='subscriptions1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub'>
                <subscriptions node='somenode'/>
              </pubsub>
            </iq>
            */
            return new PubSubIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                    Subscriptions = new Subscriptions { Node = node }
                },
            };
        }

        public static Iq RequestSubscriptionsList(Jid to, string node)
        {
            /*
            <iq type='get'
                from='hamlet@denmark.lit/elsinore'
                to='pubsub.shakespeare.lit'
                id='subman1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
                <subscriptions node='princely_musings'/>
              </pubsub>
            </iq>
            */
            return new PubSubOwnerIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                    Subscriptions = new Xmpp.PubSub.Owner.Subscriptions{ Node = node }
                },
            };
        }

        /// <summary>
        /// Requests all items stanza.
        /// </summary>
        /// <param name="to">To.</param>
        /// <param name="node">The node.</param>
        /// <returns>Iq.</returns>
        public static Iq RequestAllItems(Jid to, string node)
        {
            /*
            <iq type='get'
                from='francisco@denmark.lit/barracks'
                to='pubsub.shakespeare.lit'
                id='items1'>
              <pubsub xmlns='http://jabber.org/protocol/pubsub'>
                <items node='princely_musings'/>
              </pubsub>
            </iq>
            */
            return new PubSubIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                    Items = new Xmpp.PubSub.Items
                    {
                        Node = node
                    }
                },
            };
        }

        public static Iq RequestItem(Jid to, string node, string id)
        {
            /*
            Example 6. Subscriber requests last item by ItemID¶
                <iq type='get'
                    from='romeo@montague.lit/home'
                    to='juliet@capulet.lit'
                    id='retrieve1'>
                  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
                    <items node='urn:xmpp:avatar:data'>
                      <item id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'/>
                    </items>
                  </pubsub>
                </iq>
            */

            var items = new Xmpp.PubSub.Items { Node = node };
            items.AddItem(new Item {Id = id});

            return new PubSubIq
            {
                Type = IqType.Get,
                To = to,
                PubSub =
                {
                   Items = items
                }
            };
        }
    }
}
